package trackingAlgorithms;

import java.util.ArrayList;
import java.util.LinkedList;
import matchingAlgorithms.*;
import algos.Geometry;
import algos.Isovist;
import camera.AbstractCamera;
import com.jme3.math.Vector3f;
import java.awt.Point;
/**
 * This class is responsible for updating matching and assignment
 * 
 */
public class TrackerUpdate {
	
	private int ccc = 0;
	private final int REFRESH_RATE = 30;
	private int prevSize = -1;
	private ArrayList<Vector3f> blobs;
	private ArrayList<AbstractCamera> cameras;
	public int[]matching;
	private AbstractMatching matchingAlgo;
	public LinkedList<Vector3f>from;
	public LinkedList<Vector3f>to;
	Isovist[] iso;
	
	
	public TrackerUpdate(ArrayList<AbstractCamera> cameras){
		matchingAlgo = new HungarianMatching();
		this.cameras = cameras;
	}
	
	public void setBlobs(ArrayList<Vector3f> blobs) {
		this.blobs = blobs;
	}
	
	/**
     * @return the matching array
     *
     */
	private int[] match(){
		return matchingAlgo.match(buildGraph());
	}
    /**
     * build bipartite graph
     * @return assignment array 
     */
	 private float[][] buildGraph() {
	        boolean[][] picks = new boolean[cameras.size()][blobs.size()];
	        for (int i = 0; i < cameras.size(); i++) 
	            for (int j = 0; j < blobs.size(); j++) 
	                picks[i][j] = isInsideVisibilityPolygon(cameras.get(i), blobs.get(j),i);
	            
	        
	        return matchingAlgo.buildGraph(cameras, blobs, picks);

	 }
	 /**
	  * This function checks whether the tracked objects lay inside visibility polygon on the camera or not
	  * @param cam  tracking camera
	  * @param model  tracked object
	  * @param index  object index in objects array
	  * @return  true if the tracked object is inside visibily polygon
	  * 		 false otherwise
	  */
	 public boolean isInsideVisibilityPolygon(AbstractCamera cam, Vector3f model,int index){
             return iso[index].polygon.contains(new Point((int)model.x, (int)model.z));
	 }
/**
 * 	update cameras direction or rebuild matching bipartite graph.
 * @param blobs
 * 				detected blobs positions array
 * @param iso
 * 				visibility polygons array 
 */
	public void update(ArrayList<Vector3f> blobs, Isovist[] iso){
		this.iso = iso; 
		from = new LinkedList<Vector3f>();
		to = new LinkedList<Vector3f>();
		this.blobs = blobs;
		 if (ccc++ % REFRESH_RATE > 0 && prevSize == blobs.size()) {
                     for (int i = 0; i < matching.length; i++) {
                         if (matching[i] == -1) {
                             continue;
                         }
                         Vector3f modelPos = new Vector3f(blobs.get(matching[i]));
                         from.add(cameras.get(i).getLocation());
                         to.add(modelPos);
                         cameras.get(i).updateCamera(modelPos);                           
                }
         } else {     // if coutner % REFRESH_RATE < 0 or number of blobs changed build graph again
             prevSize = blobs.size();
             ccc = 1;
             matching = match();
         }
	}
	
}
